<?php
/**
 * --------------------------------------------------------------------
 * MCore精简框架
 * 作者：阿枫，QQ：52037872，Email：support@mdeve.com
 * --------------------------------------------------------------------
 *
 * SVN revision information:
 * @version $Revision: 1 $:
 * @author  $Author: zy $:
 * @date      $Date: 2017-03-10 21:12:21 +0800 (星期五, 10 三月 2017) $:
 */

/**
 * 导入引用的文件
 * @param string $file_name 引用的文件名
 * @return string
 */
function fimport($file_name){
    static $sufix = array(
        'action'=>'.action',
        'module'=>'.module',
        'service'=>'.service',
        'class'=>'.class',
        'function' => '.func',
        'include' => '.inc',
        'cache' => '.cache',
    );

    $file_name = strtolower($file_name);
    if(strstr($file_name, '/'))	{
        list($pre, $name) = explode('/', $file_name);
        return CORE_PATH. "/{$pre}/{$name}".$sufix[$pre].".php";
    }else{
        return CORE_PATH. "/{$file_name}.php";
    }
}

/**
 * 从绝对路径中提取相对路径
 * @param path $absolutely_path
 * @return relative path
 */
function relative_path($absolutely_path){
    global $config;
    $path = str_replace($config["INSTALL_PATH"], "", $absolutely_path);
    $path = str_replace("\\", "/", $path);
    return $path;
}

/**
 * 返回当前文件的相对目录
 * @param string $path 在调用程序中直接传参数 __FILE__ 获取当前文件的路径
 * @return string 相对路径
 */
function current_relative_path($path){
    return relative_path(dirname($path));
}


/**
 * 浏览器友好的变量输出
 * @param $var 要显示的变量
 * @param boolean $echo 是否输出
 * @return NULL|string
 */
function dump($var, $echo=true, $label=null, $strict=true) {
    $label = ($label === null) ? '' : rtrim($label) . ' ';
    if (!$strict) {
        if (ini_get('html_errors')) {
            $output = print_r($var, true);
            $output = "<pre>" . $label . htmlspecialchars($output, ENT_QUOTES) . "</pre>";
        } else {
            $output = $label . print_r($var, true);
        }
    } else {
        ob_start();
        var_dump($var);
        $output = ob_get_clean();
        if (!extension_loaded('xdebug')) {
            $output = preg_replace('/\]\=\>\n(\s+)/m', "] => ", $output);
            $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
        }
    }
    if ($echo) {
        echo($output);
        return null;
    }else
        return $output;
}

/**
 * 判断是否为有效的日期字符串
 * @param string $d 日期字符串
 * @return boolean
 */
function valid_date($d){
    return strtotime($d)>0 ? true : false;
}

/**
 * 判断是否手机号码
 * @param string $str
 * @return boolean
 */
function valid_mobile($mobile)
{
    if (strlen($mobile) != 11) return false;
    if (preg_match('/1[34578]{1}\d{9}/', $mobile)) {
        return true;
    } else {
        return false;
    }
}

/**
 * Validate an email address.
 * Provide email address (raw input)
 * Returns true if the email address has the email
 * address format and the domain exists.
 */
function valid_email($email)
{
    $isValid = true;
    if (strlen($email) < 6) return false;
    $atIndex = strrpos($email, "@");
    if (is_bool($atIndex) && !$atIndex) {
        $isValid = false;
    } else {
        $domain = substr($email, $atIndex + 1);
        $local = substr($email, 0, $atIndex);
        $localLen = strlen($local);
        $domainLen = strlen($domain);
        if ($localLen < 1 || $localLen > 64) {
            // local part length exceeded
            $isValid = false;
        } else if ($domainLen < 1 || $domainLen > 255) {
            // domain part length exceeded
            $isValid = false;
        } else if ($local [0] == '.' || $local [$localLen - 1] == '.') {
            // local part starts or ends with '.'
            $isValid = false;
        } else if (preg_match('/\\.\\./', $local)) {
            // local part has two consecutive dots
            $isValid = false;
        } else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain)) {
            // character not valid in domain part
            $isValid = false;
        } else if (preg_match('/\\.\\./', $domain)) {
            // domain part has two consecutive dots
            $isValid = false;
        } else if (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/', str_replace("\\\\", "", $local))) {
            // character not valid in local part unless
            // local part is quoted
            if (!preg_match('/^"(\\\\"|[^"])+"$/', str_replace("\\\\", "", $local))) {
                $isValid = false;
            }
        }
        if ($isValid && !(checkdnsrr($domain, "MX") || checkdnsrr($domain, "A"))) {
            // domain not found in DNS
            $isValid = false;
        }
    }
    return $isValid;
}

/**
 * 判断是否是微信浏览器
 * @return bool
 */
function is_weixin() {
    if (isset($_SERVER['HTTP_USER_AGENT'])) {
        if (strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false) {
            return true;
        }
    }
    return false;
}
/**
 * 获取客户端平台
 * @return string
 */
function check_platform()
{
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'iPhone') || strpos($_SERVER['HTTP_USER_AGENT'], 'iPad')) {
        return "ios";
    } else if (strpos($_SERVER['HTTP_USER_AGENT'], 'Android')) {
        return "android";
    } else {
        return "other";
    }
}


function is_mobile_visit(){
    // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
    if (isset ($_SERVER['HTTP_X_WAP_PROFILE'])) {
        return true;
    }
    // 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
    if (isset ($_SERVER['HTTP_VIA'])) {
        // 找不到为flase,否则为true
        return stristr($_SERVER['HTTP_VIA'], "wap") ? true : false;
    }
    // 脑残法，判断手机发送的客户端标志,兼容性有待提高
    if (isset ($_SERVER['HTTP_USER_AGENT'])) {
        $clientkeywords = array('iphone', 'android', 'phone', 'mobile', 'wap', 'netfront', 'java', 'opera mobi', 'opera mini',
            'ucweb', 'windows ce', 'symbian', 'series', 'webos', 'sony', 'blackberry', 'dopod', 'nokia', 'samsung',
            'palmsource', 'xda', 'pieplus', 'meizu', 'midp', 'cldc', 'motorola', 'foma', 'docomo', 'up.browser',
            'up.link', 'blazer', 'helio', 'hosin', 'huawei', 'novarra', 'coolpad', 'webos', 'techfaith', 'palmsource',
            'alcatel', 'amoi', 'ktouch', 'nexian', 'ericsson', 'philips', 'sagem', 'wellcom', 'bunjalloo', 'maui', 'smartphone',
            'iemobile', 'spice', 'bird', 'zte-', 'longcos', 'pantech', 'gionee', 'portalmmm', 'jig browser', 'hiptop',
            'benq', 'haier', '^lct', '320x320', '240x320', '176x220');
        // ipad访问电脑站
        if (preg_match("/ipad/i", strtolower($_SERVER['HTTP_USER_AGENT']))) {
            return false;
        }
        // 从HTTP_USER_AGENT中查找手机浏览器的关键字
        if (preg_match("/(" . implode('|', $clientkeywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT']))) {
            return true;
        }
    }
    // 协议法，因为有可能不准确，放到最后判断
    if (isset ($_SERVER['HTTP_ACCEPT'])) {
        // 如果只支持wml并且不支持html那一定是移动设备
        // 如果支持wml和html但是wml在html之前则是移动设备
        if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))) {
            return true;
        }
    }
    return false;
}

/**
 * 字节格式化 把字节数格式为 B K M G T 描述的大小
 * @return string
 */
function byte_format($size, $dec = 2)
{
    $a = array("B", "KB", "MB", "GB", "TB", "PB");
    $pos = 0;
    while ($size >= 1024) {
        $size /= 1024;
        $pos++;
    }
    return round($size, $dec) . " " . $a[$pos];
}

/**
 * 清除字符串中的特殊符号，防止SQL注入和程序注入
 * @param string $s
 * @return string
 */
function clear_string($s)
{
    return trim(str_replace(array("'", "\"", "%"), "", $s));
}

/**
 * 清除字符串中的特殊符号和HTML标签
 * @param unknown $s
 */
function clear_html($s)
{
    $s = clear_string(strip_tags($s));
    $s = trim(str_replace(array("&nbsp;"), "", $s));
    return $s;
}

/**
 * 通过UTC获取精确时间
 * 默认为北京时间
 * @param $timezone 时区，默认为 +8
 * @param $timestamp 是否返回unix时间戳格式
 */
function getutctime($timezone = 8, $timestamp = 0)
{
    $fp = fsockopen('time.nist.gov', 13, $err_no, $err_str, 90);
    $t = fread($fp, 2096);
    if (!strlen($t)) return false;
    $arr = explode(" ", $t);
    $t = $this->dateadd('hour', $timezone, strtotime($arr[1] . " " . $arr[2]));
    return $timestamp ? $t : date("Y-m-d H:i:s", $t);
}

/**
 * 中断程序并提示错误，通常用检测到严重错误
 * @param string $msg 错误提示文本
 */
function halt($msg){
    echo $msg;
    exit();
}

/**
 * 输出不允许客户端缓存的文件头，通常用于ajax
 */
function header_nocache(){
    header("Content-type: text/html; charset=utf-8");
    header("Expires: Mon, 26 Jul 1970 05:00:00  GMT");
    header("Last-Modified:" . gmdate("D, d M Y  H:i:s")  . "GMT");
    header("Cache-Control:no-cache, must-revalidate");
    header("Pragma:no-cache");
}

/**
 * 输出ajax提示
 * @param string $status 返回状态，分为 error 和 successful 两种，或在前台javascript中自行判断
 * @param json $msg 直接输出的json字符串
 */
function ajax_result($status="successful", $msg=""){
    header_nocache();
    exit(json_encode(array('status'=>$status, 'msg'=>$msg)));
}

function javascript_result($script) {
    header_nocache();
    exit("<script type=\"text/javascript\">{$script}</script>");
}

/**
 * 获取客户端IP地址
 * @return ip
 */
function get_client_ip()
{
    if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown"))
        $ip = getenv("HTTP_CLIENT_IP");
    else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown"))
        $ip = getenv("HTTP_X_FORWARDED_FOR");
    else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown"))
        $ip = getenv("REMOTE_ADDR");
    else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown"))
        $ip = $_SERVER['REMOTE_ADDR'];
    else
        $ip = "unknown";

    // 如果返回多个IP，则只取第一个。
    if (strpos($ip, ",")) {
        $ips = explode(",", $ip);
        $ip = $ips[0];
    }

    return ($ip);
}

function get_http_user_agent()
{
    return $_SERVER['HTTP_USER_AGENT'] ?? "";
}

/**
 * 将日期格式根据以下规律修改为不同显示样式
 * 小于1分钟 则显示多少秒前
 * 小于1小时，显示多少分钟前
 * 一天内，显示多少小时前
 * 3天内，显示前天22:23或昨天:12:23。
 * 超过3天，则显示完整日期。
 * @static
 * @param $sorce_date 数据源日期 unix时间戳
 * @return void
 */
function getDateStyle($sorce_date)
{
    if (!is_numeric($sorce_date)) $sorce_date = strtotime($sorce_date);
    $nowTime = time(); //获取今天时间戳
    // echo '数据源时间戳：'.$sorce_date . ' = '. date('Y-m-d H:i:s',$sorce_date);
    // echo "\n 当前时间戳:". date('Y-m-d H:i:s',$nowTime)."\n";
    $timeHtml = ''; //返回文字格式
    $temp_time = 0;
    switch ($sorce_date) {
        //一分钟
        case ($sorce_date + 60) >= $nowTime:
            $temp_time = $nowTime - $sorce_date;
            $timeHtml = intval($temp_time) . "秒前";
            break;
        //小时
        case ($sorce_date + 3600) >= $nowTime:
            $temp_time = date('i', $nowTime - $sorce_date);
            $timeHtml = intval($temp_time) . "分钟前";
            break;
        //天
        case ($sorce_date + 3600 * 24) >= $nowTime:
            $temp_time = ($nowTime - $sorce_date) / 3600;
            $timeHtml = intval($temp_time) . '小时前';
            break;
        //昨天
        case ($sorce_date + 3600 * 24 * 2) >= $nowTime:
            $temp_time = date('H:i', $sorce_date);
            $timeHtml = '昨天' . $temp_time;
            break;
        //前天
        case ($sorce_date + 3600 * 24 * 3) >= $nowTime:
            $temp_time = date('H:i', $sorce_date);
            $timeHtml = '前天' . $temp_time;
            break;
        //3天前
        case ($sorce_date + 3600 * 24 * 4) >= $nowTime:
            $temp_time = date('H:i', $sorce_date);
            $timeHtml = '3天前' . $temp_time = date('H:i', $sorce_date);;
            break;
        // 1年前
        case ($sorce_date - $nowTime) > 3600 * 24 * 365:
            $timeHtml = date('Y年m月d日 H:i', $sorce_date);
            break;
        default:
            $timeHtml = date('m月d日 H:i', $sorce_date);
            break;
    }
    return $timeHtml;
}


/**
 * 将秒数格式化为 XX小时XX分XX秒
 * @param $time
 * @return int|string
 */
function format_second($time) {
    $output = '';
    foreach (array(86400 => '天', 3600 => '小时', 60 => '分', 1 => '秒') as $key => $value) {
        if ($time >= $key) $output .= floor($time/$key) . $value;
        $time %= $key;
    }
    if($output==''){
        $output=0;
    }
    return $output;
}

/**
 * 解开javascipt的escape
 * @param string $url
 * @return string
 */
function unicode_urldecode($url)
{
    preg_match_all('/%u([[:alnum:]]{4})/', $url, $a);

    foreach ($a[1] as $uniord) {
        $dec = hexdec($uniord);
        $utf = '';

        if ($dec < 128) {
            $utf = chr($dec);
        } else if ($dec < 2048) {
            $utf = chr(192 + (($dec - ($dec % 64)) / 64));
            $utf .= chr(128 + ($dec % 64));
        } else {
            $utf = chr(224 + (($dec - ($dec % 4096)) / 4096));
            $utf .= chr(128 + ((($dec % 4096) - ($dec % 64)) / 64));
            $utf .= chr(128 + ($dec % 64));
        }

        $url = str_replace('%u' . $uniord, $utf, $url);
    }
    return urldecode($url);
}

/**
 * 将字符串打包成 javascript 的 escape 格式
 *
 * @param unknown_type $str
 * @return string
 */
function unicode_escape($str)
{
    $sublen = strlen($str);
    $retrunString = "";
    for ($i = 0; $i < $sublen; $i++) {
        if (ord($str [$i]) >= 127) {
            $tmpString = $str;
            // $tmpString=substr($tmpString,2,2).substr($tmpString,0,2);window下可能要打开此项
            $retrunString .= "%u" . $tmpString;
            $i++;
        } else {
            $retrunString .= "%" . dechex(ord($str [$i]));
        }
    }
    return $retrunString;
}

/**
 * 验证身份证号
 *
 * @param
 *            $vStr
 * @return bool
 */
function isCreditNo($vStr)
{
    $vCity = array(
        '11', '12', '13', '14', '15', '21', '22',
        '23', '31', '32', '33', '34', '35', '36',
        '37', '41', '42', '43', '44', '45', '46',
        '50', '51', '52', '53', '54', '61', '62',
        '63', '64', '65', '71', '81', '82', '91'
    );

    if (!preg_match('/^([\d]{17}[xX\d]|[\d]{15})$/', $vStr))
        return false;

    if (!in_array(substr($vStr, 0, 2), $vCity))
        return false;

    $vStr = preg_replace('/[xX]$/i', 'a', $vStr);
    $vLength = strlen($vStr);

    if ($vLength == 18) {
        $vBirthday = substr($vStr, 6, 4) . '-' . substr($vStr, 10, 2) . '-' . substr($vStr, 12, 2);
    } else {
        $vBirthday = '19' . substr($vStr, 6, 2) . '-' . substr($vStr, 8, 2) . '-' . substr($vStr, 10, 2);
    }

    if (date('Y-m-d', strtotime($vBirthday)) != $vBirthday)
        return false;
    if ($vLength == 18) {
        $vSum = 0;

        for ($i = 17; $i >= 0; $i--) {
            $vSubStr = substr($vStr, 17 - $i, 1);
            $vSum += (pow(2, $i) % 11) * (($vSubStr == 'a') ? 10 : intval($vSubStr, 11));
        }

        if ($vSum % 11 != 1)
            return false;
    }

    return true;
}


function create_random_str($length){
    $str = array_merge(range(0,9),range('a','z'),range('A','Z'));
    shuffle($str);
    $str = implode('',array_slice($str,0,$length));
    return $str;
}

function __autoload($name) {
    header("Content-type: text/html; charset=utf-8");
    echo "无法加载 {$name}";
    exit;
}


/**
 * utf8字符转换成Unicode字符
 * @param  [type] $utf8_str Utf-8字符
 * @return [type]           Unicode字符
 */
function utf8_str_to_unicode($utf8_str) {
    $unicode = 0;
    $unicode = (ord($utf8_str[0]) & 0x1F) << 12;
    $unicode |= (ord($utf8_str[1]) & 0x3F) << 6;
    $unicode |= (ord($utf8_str[2]) & 0x3F);
    return dechex($unicode);
}

/**
 * Unicode字符转换成utf8字符
 * @param  [type] $unicode_str Unicode字符
 * @return [type]              Utf-8字符
 */
function unicode_to_utf8($unicode_str) {
    $utf8_str = '';
    $code = intval(hexdec($unicode_str));
    //这里注意转换出来的code一定得是整形，这样才会正确的按位操作
    $ord_1 = decbin(0xe0 | ($code >> 12));
    $ord_2 = decbin(0x80 | (($code >> 6) & 0x3f));
    $ord_3 = decbin(0x80 | ($code & 0x3f));
    $utf8_str = chr(bindec($ord_1)) . chr(bindec($ord_2)) . chr(bindec($ord_3));
    return $utf8_str;
}

/**
 * 检查字符串是否是UTF8编码
 * @param string $string 字符串
 * @return Boolean
 */
function is_utf8($string)
{
    return preg_match('%^(?:
		 [\x09\x0A\x0D\x20-\x7E]            # ASCII
			| [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
			|  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
			| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
			|  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
			|  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
			| [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
			|  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
	)*$%xs', $string);
}